//
//  MQTTSessionManager.m
//  MQTTNetworkTools
//
//  Created by Yahaong on 16/8/2.
//  Copyright © 2016年 yahaong. All rights reserved.
//

#import "MQTTSessionManager.h"
#import "XAIGateway.h"
#import "GlobalConst.h"
#import "ZTLinkageUtil.h"
#import "ZTDeviceUtil.h"
#import "JPUSHService.h"
#import <XAISDK/XAIPKTDev.h>
#import <XAISDK/XAIPKTIM.h>
#import <XAISDK/XAIPKTConfig.h>
#import <XAISDK/XAI.h>
#import <XAISDK/XAIPKTControl.h>
#import <XAISDK/XAIPKT.h>
#import <XAISDK/XAIFormatDataCount.h>
#import <XAISDK/XAILUIDUtil.h>
#import <XAISDK/XAIAPSNUtil.h>
#import <XAISDK/XAIConvertorHelper.h>
#import "NetworkMonitorUtils.h"
#import "ZTLinkageUtil.h"
#import "ZTDeviceUtil.h"
#import "ZTLCCamera.h"
#import "ZTNoControlDevice.h"
#import "ZTOneControlDevice.h"
#import "ZTTwoControlDevice.h"
#import "ZTThreeControlDevice.h"
#import "ZTFourControlDevice.h"
#import "ZTAirMonitorDevice.h"
#import "XAIGateway.h"
#import "Friend.h"
#import "GatewayPermitView.h"
#import "ZTGatewayBindModel.h"
#import "YSHUD.h"
#import "JSQMessages.h"
#import "IMConfig.h"
#import "DataBaseManager.h"

static MQTTSessionManager *_instance = nil;

@interface MQTTSessionManager ()
@property (nullable, nonatomic, strong) DataManager* dataManager;
@end

@implementation MQTTSessionManager

+ (instancetype)sharedManager
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc]init];
    });
    return _instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _netWorkStatus = YES;
        [[NetworkMonitorUtils shared] startListen];
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(netWorkStatusChanged:) name:NetWorkDidChangeNotification object:nil];
    }
    return self;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

#pragma mark - XAIDelegate

- (void)gatewayDetected:(XAI *)xai gatewayApsn:(uint32_t)gatewayApsn gatewayLuid:(uint64_t)gatewayLuid {
    if (![self.currentUser alreadyBindGateway]) {
        self.currentUser.currentBindApsn = gatewayApsn;
        [self.currentUser archiver];
    }
    XAIGateway* gateway = [kDataManager fetchGatewayWithApsn:gatewayApsn luid:gatewayLuid];
    if (!gateway) {
        gateway = [[XAIGateway alloc] initWithApsn:gatewayApsn Luid:gatewayLuid type:ZTDeviceTypeGateWay];
        [self.dataManager addGateway:gateway];
    }
    if (self.currentUser.currentBindApsn == gateway.apsn) {
        self.currentGateway = gateway;
    }
    [self.dataManager gatewayCallBack];
}

- (void)gatewayRemoved:(XAI *)xai gatewayApsn:(uint32_t)gatewayApsn gatewayLuid:(uint64_t)gatewayLuid {
    [kDataManager removeDeviceWithApsn:gatewayApsn];
    [kDataManager removeLinkageWithApsn:gatewayApsn];
    [kDataManager removeGatewayWithApsn:gatewayApsn];
    if (kDataManager.gatewayListenList.count > 0) {
        XAIGateway *gateway =  [kDataManager.gatewayListenList firstObject];
        kMQTTSessionManager.currentGateway = gateway;
        kMQTTSessionManager.currentUser.currentBindApsn = gateway.apsn;
        [kMQTTSessionManager.currentUser archiver];
    } else {
        kMQTTSessionManager.currentGateway = nil;
        kMQTTSessionManager.currentUser.currentBindApsn = 0;
        [kMQTTSessionManager.currentUser archiver];
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter]postNotificationName:kZTSwitchGatewayNotifKey object:nil];
    });
    [kDataManager gatewayCallBackWithType:GatewayCallbackTypeName];
    [kDataManager linkageCallBack];
}

- (void)deviceDetected:(XAI *)xai deviceApsn:(uint32_t)deviceApsn deviceLuid:(uint64_t)deviceLuid deviceType:(uint32_t)deviceType version:(uint32_t)version des:(NSString * _Nullable)des {
    if (deviceType == ZTDeviceTypeZTDoorsensor
        || deviceType == ZTDeviceTypeInfraredDetector
        || deviceType == ZTDeviceTypeAlarmkey) {
        ZTNoControlDevice *dev = [[ZTNoControlDevice alloc]initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:dev];
    } else if (deviceType == ZTDeviceTypeOneWay0Switch
             || deviceType == ZTDeviceTypeOneWaySwitch
             || deviceType == ZTDeviceTypeOneWaySocket
             || deviceType == ZTDeviceTypeSmoke
             || deviceType == ZTDeviceTypeGAS
             || deviceType == ZTDeviceTypeFlooding
             || deviceType == ZTDeviceTypeCurtainSingleTrack
             ) {
        ZTOneControlDevice *ctlDevice = [[ZTOneControlDevice alloc]initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:ctlDevice];
    } else if (deviceType == ZTDeviceTypeTwoWay0Switch
             || deviceType == ZTDeviceTypeTwoWaySwitch
             || deviceType == ZTDeviceTypeTwoWaySocket
             || deviceType == ZTDeviceTypeCurtainDoubleTrack
             ) {
        ZTTwoControlDevice *ctlDevice = [[ZTTwoControlDevice alloc]initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:ctlDevice];
    } else if (deviceType == ZTDeviceTypeThreeWay0Switch
             || deviceType == ZTDeviceTypeThreeWaySwitch
             || deviceType == ZTDeviceTypeThreeWaySocket
             ) {
        ZTThreeControlDevice *ctlDevice = [[ZTThreeControlDevice alloc]initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:ctlDevice];
    } else if (deviceType == ZTDeviceTypeFourWay0Switch
             ||deviceType == ZTDeviceTypeFourWaySwitch
             ||deviceType == ZTDeviceTypeFourWaySocket
             ) {
        ZTFourControlDevice *ctlDevice = [[ZTFourControlDevice alloc]initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:ctlDevice];
    } else if (deviceType == ZTDeviceTypeLCCamera) {
        ZTLCCamera* camera = [[ZTLCCamera alloc] initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:camera];
    } else if (deviceType == ZTDeviceTypeAir) {
        ZTAirMonitorDevice* airMonitor = [[ZTAirMonitorDevice alloc] initWithApsn:deviceApsn Luid:deviceLuid type:deviceType];
        [self.dataManager addDevice:airMonitor];
    }
    [kDataManager deviceRefreshCallBackWithType:DeviceCallbackTypeName];
}

- (void)deviceRemoved:(XAI *)xai deviceApsn:(uint32_t)deviceApsn deviceLuid:(uint64_t)deviceLuid {
    [kDataManager removeDeviceWithApsn:deviceApsn luid:deviceLuid];
    [kDataManager deviceRefreshCallBackWithType:DeviceCallbackTypeName];
}

- (void)friendDetected:(XAI *)xai friendApsn:(uint32_t)friendApsn mobile:(NSString *)mobile {
    Friend* friend = [[Friend alloc] initWithMobile:mobile apsn:friendApsn];
    [kDataManager addFriend:friend];
    [kDataManager friendRefreshCallBackWithType:FriendCallbackTypeName];
}

- (void)friendRemoved:(XAI *)xai friendApsn:(uint32_t)friendApsn mobile:(NSString *)mobile {
    [kDataManager removeFriendWithApsn:friendApsn mobile:mobile];
    [kDataManager friendRefreshCallBackWithType:FriendCallbackTypeName];
}

- (void)linkDetected:(XAI *)xai
              linkID:(uint8_t)linkID
         gatewayApsn:(uint32_t)gatewayApsn
            linkName:(NSString *)linkName
              active:(BOOL)active
          conditions:(NSArray<XAILinkItemDes *> *)conditions
             actions:(NSArray<XAILinkItemDes *> *)actions {

    ZTLinkage *linkage = [[ZTLinkage alloc]init];
    linkage.gatewayApsn = gatewayApsn;
    linkage.num = linkID;
    linkage.status = active;
    linkage.name = linkName;
    linkage.actionInfos = [NSMutableArray arrayWithArray:actions];
    linkage.condInfos = [NSMutableArray arrayWithArray:conditions];
    [kDataManager addLinkage:linkage];
    if (linkage.gatewayApsn == self.currentUser.currentBindApsn) {
        [kDataManager linkageCallBack];
    }
}

- (void)linkRemoved:(XAI *)xai gatewayApsn:(uint32_t)gatewayApsn linkID:(uint8_t)linkID {
    //联动删除
    if ([kDataManager removeLinkageWithApsn:gatewayApsn linkID:linkID]) {
        [kDataManager linkageCallBack];
    }
}

- (void)statusMessageRecived:(XAI *)xai
                  deviceApsn:(XAITYPEAPSN)deviceApsn
                  deviceLuid:(XAITYPELUID)deviceLuid
                 triggerApsn:(XAITYPEAPSN)triggerApsn
                 triggerLuid:(XAITYPELUID)triggerLuid
                   timestamp:(XAITYPETIME)timestamp
                    statusID:(uint8_t)statusID
                        data:(XAITLV *)data
                   isHistory:(BOOL)isHistory {

        if ([XAILUIDUtil isServerAP:deviceLuid] && [XAIAPSNUtil isGateway: deviceApsn]) {
            XAIGateway *gateway = [kDataManager fetchGatewayWithApsn:deviceApsn luid:deviceLuid];
            if (gateway) {
                [gateway reciveStatus:deviceApsn
                           deviceLuid:deviceLuid
                          triggerApsn:triggerApsn
                          triggerLuid:triggerLuid
                            timestamp:timestamp
                             statusID:statusID
                                 data:data
                            isHistory:isHistory];
            }
        }
        else if([XAILUIDUtil isNode:deviceLuid] && [XAIAPSNUtil isGateway:deviceApsn] && ![XAIAPSNUtil isCloud:deviceApsn]) {
            ZTDevice *device = [kDataManager fetchDeviceWithApsn:deviceApsn luid:deviceLuid];
            if (device) {
                [device reciveStatus:deviceApsn
                          deviceLuid:deviceLuid
                         triggerApsn:triggerApsn
                         triggerLuid:triggerLuid
                           timestamp:timestamp
                            statusID:statusID
                                data:data
                           isHistory:isHistory];
            }
        } else if ([XAILUIDUtil iSMobile:deviceLuid]  && [XAIAPSNUtil isCloud: deviceApsn]) {
            Friend *friend = [kDataManager fetchFriendWithApsn:deviceApsn luid:deviceLuid];
            if (friend) {
                [friend reciveStatus:deviceApsn
                          deviceLuid:deviceLuid
                         triggerApsn:triggerApsn
                         triggerLuid:triggerLuid
                           timestamp:timestamp
                            statusID:statusID
                                data:data
                           isHistory:isHistory];
            }
        }
}

- (void)CMDMessageRecived:(XAI *)xai deviceApsn:(uint32_t)deviceApsn deviceLuid:(uint64_t)deviceLuid timestamp:(uint32_t)timestamp cmdID:(uint8_t)cmdID datas:(NSArray<XAITLV *> *)datas {
    if ([XAILUIDUtil isCloudServer:deviceApsn luid:deviceLuid]) {
        if (1 == cmdID) {
            if (datas.count < 4) {
                return;
            }
            XAITYPEAPSN applyApsn = 0;
            XAITYPELUID applyLuid = 0;
            XAITYPEAPSN triggerApsn = 0;
            XAITYPELUID triggerLuid = 0;
            XAITLV* tlv = datas[0];
            if (tlv.payloadlen != sizeof(applyApsn)) {
                return;
            }
            applyApsn = [XAIConvertorHelper bytesToInt:[tlv getPayloadbyte]  offset:0];
            applyApsn = CFSwapInt32(applyApsn);
            tlv = datas[1];
            applyLuid = [XAIConvertorHelper bytesToLong:[tlv getPayloadbyte]  offset:0];
            applyLuid = CFSwapInt64(applyLuid);
            tlv = datas[2];
            triggerApsn = [XAIConvertorHelper bytesToInt:[tlv getPayloadbyte]  offset:0];
            triggerApsn = CFSwapInt32(triggerApsn);
            tlv = datas[3];
            triggerLuid = [XAIConvertorHelper bytesToLong:[tlv getPayloadbyte]  offset:0];
            triggerLuid = CFSwapInt64(triggerLuid);
            NSString* info = nil;
            if (datas.count == 5) {
                tlv = datas[4];
                info = [[NSString alloc]initWithBytes:[tlv getPayloadbyte] length:tlv.payloadlen encoding:NSUTF8StringEncoding];
            }
            ZTGatewayBindModel* gatewayBindModel = [[ZTGatewayBindModel alloc]init];
            gatewayBindModel.applyApsn = applyApsn;
            gatewayBindModel.applyLuid = applyLuid;
            gatewayBindModel.triggerApsn = triggerApsn;
            gatewayBindModel.triggerLuid = triggerLuid;
            gatewayBindModel.info = info;
            if (self.isSHowHomeed) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [YSHUD showGatewayPermit:gatewayBindModel];
                });
            } else {
                [kDataManager.bindGateModels addObject:gatewayBindModel];
            }
        }
    }
}

- (void)IMMessageRecived:(XAI *)xai
              deviceApsn:(uint32_t)deviceApsn
              deviceLuid:(uint64_t)deviceLuid
               timestamp:(uint32_t)timestamp
                    data:(XAITLV *)data {

    [kDataBaseManager storeIMMessagefromApsn:deviceApsn fromLuid:deviceLuid toApsn:kZTCloudGatewayApsn toLuid:kMQTTSessionManager.currentUser.luid type:1 isRead:0 timestamp:timestamp data:data];
    [kDataManager imMessageCallBack];
}

- (void)pushDetected:(XAI *)xai gatewayApsn:(XAITYPEAPSN)gatewayApsn active:(BOOL)active {
    
    NSLog(@"%08x active = %zd",gatewayApsn, active);
    NSArray* gateways = [kDataManager.gatewayListenList copy];
    XAIGateway* findGateway = nil;
    @synchronized (kDataManager.gatewayListenList) {
        for (XAIGateway* gateway in gateways) {
            if (gateway.apsn == gatewayApsn)
            {
                findGateway = gateway;
            }
        }
    }
    if (findGateway) {
        findGateway.pushActive = active;
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter]postNotificationName:@"kZTProtectChangeNotifKey" object:@(active)];
    });
}
#pragma mark - private method
- (void)showOfflineMessage
{
    if (kDataManager.bindGateModels.count == 0) {
        return;
    }
    for (ZTGatewayBindModel* model in kDataManager.bindGateModels)
    {
        [YSHUD showGatewayPermit:model];
    }
}

#pragma mark - NetworkChange 网络状态变化

- (void)netWorkStatusChanged:(NSNotification *)nofiy {
    NSDictionary *info = nofiy.userInfo;
    if (info && info[@"status"]) {
        NSNumber *status = info[@"status"];
        self.netWorkStatus = [status boolValue];
        if (self.netWorkStatus) {
            debugLogInfo(@"有网络");
            if ((self.xai.connectStatus == XAINotConnected)) {
                [self.xai startWithAccount:self.currentUser.m_strTel password:self.currentUser.m_strPwd success:^{
                    
                } error:^(NSUInteger code) {
                    
                }];
            }
        } else {
            debugLogInfo(@"无网络");
            if (self.xai) {
                [self.xai close];
            }
        }
    }
}

- (void)setJPushRule:(uint32_t) apsn registerID:(NSString*)registerID enable:(BOOL)enable configs:(NSArray <XAIJPushRule*>*)configs
{
    XAIFormatDataCount* formatCount = [[XAIFormatDataCount alloc]init];
    [formatCount addDataType:XAI_DATA_TYPE_BIN_BOOL bytes:&enable length:sizeof(enable)];
    NSData* nameData = [registerID dataUsingEncoding:NSUTF8StringEncoding];
    [formatCount addDataType:XAI_DATA_TYPE_ASCII_TEXT bytes:(void*)[nameData bytes] length:(int)nameData.length];
    for (XAIJPushRule* jPushRule in configs)
    {
        NSData* pushData = [jPushRule toData];
        [formatCount addDataType:XAI_DATA_TYPE_BIN_PUSH_CONFIG bytes:(void*)[pushData bytes] length:(int)pushData.length];
    }
    XAIPKTControl* pktControl = [[XAIPKTControl alloc]init];
    pktControl.oprId = 10;
    pktControl.time = [[NSDate new] timeIntervalSince1970];
    NSData* data = [formatCount toData];
    [pktControl setPayloadbyte:(void*)[data bytes] withSize:(int)data.length];
    XAIPKT *pkt = [[XAIPKT alloc]init];
    pkt.fromApsn = self.currentUser.apsn;
    pkt.fromLuid = self.currentUser.luid;
    pkt.toApsn = apsn;
    pkt.toLuid = kGATEWAYLUID;
    pkt.flag = XAI_PKT_TYPE_CONTROL;
    pkt.magicNum = 0;
    NSData* controlData = [pktControl toData];
    [pkt setPayloadbyte:(void*)[controlData bytes] withSize:(int)controlData.length];
    return [ self send:pkt];
}

- (void)deviceDelete:(XAITYPEAPSN) apsn Luid:(XAITYPELUID)luid {
    XAIFormatDataCount* formateCount = [[XAIFormatDataCount alloc]init];
    [formateCount addDataType:XAI_DATA_TYPE_BIN_APSN bytes:&apsn length:sizeof(apsn)];
    [formateCount addDataType:XAI_DATA_TYPE_BIN_LUID bytes:&luid length:sizeof(luid)];
    [kMQTTSessionManager sendCmd:0x01 toApsn:kMQTTSessionManager.currentUser.currentBindApsn toLuid:kGATEWAYLUID data:formateCount];
}

- (void)sendMyDev:(uint32_t) type verson:(uint32_t)verson sleep:(BOOL)sleep {
    XAIPKTDev* pktDev = [[XAIPKTDev alloc]init];
    pktDev.sleep = sleep;
    pktDev.type = type;
    pktDev.verson = verson;
    pktDev.des = @"你好吗, iOS";
    XAIPKT* pkt = [[XAIPKT alloc]init];
    XAITYPEAPSN apsn = self.currentUser.apsn;
    XAITYPELUID luid = self.currentUser.luid;
    pkt.fromApsn = apsn;
    pkt.fromLuid = luid;
    pkt.toApsn =  apsn;
    pkt.toLuid =  luid;
    pkt.flag = XAI_PKT_TYPE_DEV;
    pkt.magicNum = 0;
    NSData* data = [pktDev toData];
    [pkt setPayloadbyte:(void*)[data bytes] withSize:(int)data.length];
    [self send:pkt];
}

- (void) sendDeviceDev:(uint32_t) type  verson:(uint32_t)verson sleep:(BOOL)sleep fromApsn:(XAITYPEAPSN)fromApsn fromLuid:(XAITYPELUID)fromLuid {
    XAIPKTDev* pktDev = [[XAIPKTDev alloc]init];
    pktDev.sleep = sleep;
    pktDev.type = type;
    pktDev.verson = verson;
    XAIPKT* pkt = [[XAIPKT alloc]init];
    pkt.fromApsn = fromApsn;
    pkt.fromLuid = fromLuid;
    pkt.toApsn =  fromApsn;
    pkt.toLuid =  fromLuid;
    pkt.flag = XAI_PKT_TYPE_DEV;
    pkt.magicNum = 0;
    NSData* data = [pktDev toData];
    [pkt setPayloadbyte:(void*)[data bytes] withSize:(int)data.length];
    data = [pkt toData];
    NSString* topic = [NSString stringWithFormat:@"0x%08x/NODES/0x%016llx/OUT/DEV",fromApsn,fromLuid];
//    [self sendData:data topic:topic qosValue:ExactlyOnce retain:true timeout:0];
}

- (void)deviceAdd:(XAITYPEAPSN)apsn Luid:(XAITYPELUID)luid {
    XAIFormatDataCount *formatCount = [[XAIFormatDataCount alloc]init];
    [formatCount addDataType:XAI_DATA_TYPE_BIN_APSN bytes:&apsn length:sizeof(apsn)];
    [formatCount addDataType:XAI_DATA_TYPE_BIN_LUID bytes:&luid length:sizeof(luid)];
    [self sendCmd:0x07 toApsn:apsn toLuid:kGATEWAYLUID data:formatCount];
}

- (void)sendCmd:(uint8_t)cmdID  toApsn:(XAITYPEAPSN)toApsn toLuid:(XAITYPELUID)toLuid data:(XAIFormatDataCount*)formatDataCount {
    XAIPKTControl *pktControl = [[XAIPKTControl alloc]init];
    pktControl.oprId = cmdID;
    pktControl.time = [[NSDate new] timeIntervalSince1970];
    NSData* data = [formatDataCount toData];
    [pktControl setPayloadbyte:(void*)[data bytes] withSize:(int)data.length];
    
    XAIPKT *pkt = [[XAIPKT alloc]init];
    pkt.fromApsn = kMQTTSessionManager.currentUser.apsn;
    pkt.fromLuid = kMQTTSessionManager.currentUser.luid;
    pkt.toApsn = toApsn;
    pkt.toLuid = toLuid;
    pkt.flag = XAI_PKT_TYPE_CONTROL;
    pkt.magicNum = 0;
    NSData* controlData = [pktControl toData];
    [pkt setPayloadbyte:(void*)[controlData bytes] withSize:(int)controlData.length];
//    [self send:pkt needAck:true timeOut:500];
    [self send:pkt];
}

- (void)sendMyDeviceName:(NSString* __nullable)name {
    XAITYPEAPSN apsn = kMQTTSessionManager.currentUser.apsn;
    XAITYPELUID luid = kMQTTSessionManager.currentUser.luid;
    NSData *data = [name dataUsingEncoding:NSUTF8StringEncoding];
    return [self sendStatus:StatusIDName toApsn:apsn toLuid:luid dataType:XAI_DATA_TYPE_ASCII_TEXT bytes:(void*)[data bytes] length:(int)data.length];
}

- (void)sendMyDeviceConnection:(BOOL)online {
    XAITYPEAPSN apsn = kMQTTSessionManager.currentUser.apsn;
    XAITYPELUID luid = kMQTTSessionManager.currentUser.luid;
    return [self sendStatus:StatusIDOnOff toApsn:apsn toLuid:luid dataType:XAI_DATA_TYPE_BIN_BOOL bytes:&online length:sizeof(online)];
}
- (void)sendMyDevicePower:(uint32_t)power
{
    XAITYPEAPSN apsn = kMQTTSessionManager.currentUser.apsn;
    XAITYPELUID luid = kMQTTSessionManager.currentUser.luid;
    return [self sendStatus:StatusIDPower toApsn:apsn toLuid:luid dataType:XAI_DATA_TYPE_BIN_DIGITAL_UNSIGN bytes:&power length:sizeof(power)];
}
- (void)sendStatus:(uint8_t)statusID toApsn:(XAITYPEAPSN)toApsn toLuid:(XAITYPELUID)toLuid dataType:(uint8_t) type bytes:(void*)bytes length:(int)length
{
    XAIFormatDataCount* formatCount = [[XAIFormatDataCount alloc]init];
    [formatCount addDataType:type bytes:bytes length:length];
    return [self sendStatus:statusID toApsn:toApsn toLuid:toLuid data:formatCount];
}

- (void)sendStatus:(uint8_t)statusID  toApsn:(XAITYPEAPSN)toApsn toLuid:(XAITYPELUID)toLuid data:(XAIFormatDataCount *__nullable)formatDataCount
{
    XAIPKTStatus *pktStatus = [[XAIPKTStatus alloc] init];
    pktStatus.oprId = statusID;
    pktStatus.time = [[NSDate new] timeIntervalSince1970];
    NSData* data = [formatDataCount toData];
    [pktStatus setPayloadbyte:(void*)[data bytes] withSize:(int)data.length];
    
    XAIPKT* pkt = [[XAIPKT alloc] init];
    pkt.fromApsn = kMQTTSessionManager.currentUser.apsn;
    pkt.fromLuid = kMQTTSessionManager.currentUser.luid;
    pkt.toApsn = toApsn;
    pkt.toLuid = toLuid;
    pkt.flag = XAI_PKT_TYPE_STATUS;
    pkt.magicNum = 0;
    NSData* statusData = [pktStatus toData];
    [pkt setPayloadbyte:(void*)[statusData bytes] withSize:(int)statusData.length];
    [self send:pkt];
    
}

- (void)send:(XAIPKT* __nullable)pkt
{
    NSString* topic = [self createTopicFromPkt:pkt];
    NSLog(@"topic = %@",topic);
    if (topic.length == 0)
    {
        return;
    }
    long timeout = 0;
    BOOL retain = false;
    if ([pkt isACK])
    {
        retain = false;
    }
    else
    {
        if (XAI_PKT_TYPE_DEV == pkt.flag ||XAI_PKT_TYPE_CONFIG == pkt.flag || XAI_PKT_TYPE_STATUS == pkt.flag)
        {
            retain = true;
            timeout = -1;
        }
        else if (XAI_PKT_TYPE_CONTROL == pkt.flag
                 || XAI_PKT_TYPE_IM == pkt.flag
                 || XAI_PKT_TYPE_HELLO == pkt.flag)
        {
            retain = false;
        }
        else
        {
            retain = false;
        }
    }
//    [self sendData:[pkt toData] topic:topic qosValue:ExactlyOnce retain:retain timeout:timeout];

}
- (void)sendData:(NSData*)data topic:(NSString*)topic qosValue:(int)qosValue retain:(BOOL)retain timeout:(long) timeout
{
//    [kMQTTSessionManager.mqttClient publish:(void*)[data bytes] size:(int)data.length toTopic:topic withQos:ExactlyOnce retain:retain];
}



- (NSString* __nullable)createTopicFromPkt:(XAIPKT * __nullable)pkt
{
    NSString *topicHead = [MQTTSessionManager getTopicHeadFromPkt:pkt];
    if (topicHead.length == 0) {
        return nil;
    }
    NSString *topic  = nil;
    if ([pkt isACK])
    {
        topic = [MQTTCoverTool stringFormat:@"%@/%@/%@/IN" type:topicHead APNS:pkt.toApsn luid:pkt.toLuid];
        return topic;
    }
    else
    {
        if (pkt.flag == XAI_PKT_TYPE_DEV)
        {
            topic = [MQTTCoverTool stringFormat:@"%@/%@/%@/OUT/DEV" type:topicHead APNS:pkt.toApsn luid:pkt.toLuid];
            return topic;
        }
        else if (pkt.flag == XAI_PKT_TYPE_CONFIG)
        {
            XAIPKTConfig *pktConfig = [XAIPKTConfig format:[pkt getPayloadbyte] length:pkt.payloadlen];
            if (pktConfig != nil)
            {
                if (pktConfig.type == XAIPKTConfigTypeLinkage) {
                    topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/CONFIG/LINKACTION/0x%02x",pkt.toApsn,topicHead,pkt.toLuid, [pktConfig getID]];
                    return topic;
                }
                else if (pktConfig.type == XAIPKTConfigTypePush)
                {
                    topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/CONFIG/USER/0x%016llx@0x%08x/PUSH",pkt.fromApsn,topicHead, pkt.fromLuid, pktConfig.luid,pktConfig.idApsn];
                    return topic;
                }
                else if (pktConfig.type == XAIPKTConfigTypeMessage)
                {
                    topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/CONFIG/USER/0x%016llx@0x%08x/MESSAGE",pkt.fromApsn,topicHead, pkt.fromLuid, pktConfig.luid,pktConfig.idApsn];
                    return topic;
                }
                else if (pktConfig.type == XAIPKTConfigTypeActive)
                {
                    topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/CONFIG/USER/0x%016llx@0x%08x/ACTIVE",pkt.fromApsn,topicHead, pkt.fromLuid, pktConfig.luid,pktConfig.idApsn];
                    return topic;
                }
                else if (pktConfig.type == XAIPKTConfigTypeADMin)
                {
                    topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/CONFIG/ADMIN",pkt.fromApsn,topicHead, pkt.fromLuid];
                    return topic;
                }
            }
        }
        else if (pkt.flag == XAI_PKT_TYPE_CONTROL
            || pkt.flag == XAI_PKT_TYPE_IM
            || pkt.flag == XAI_PKT_TYPE_HELLO
            )
        {
            topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/IN",pkt.toApsn,topicHead, pkt.toLuid];
            return topic;
        }
        else if (pkt.flag == XAI_PKT_TYPE_STATUS)
        {
            XAIPKTStatus *pktStatus = [XAIPKTStatus format:[pkt getPayloadbyte] length:pkt.payloadlen];
            topic = [NSString stringWithFormat:@"0x%08x/%@/0x%016llx/OUT/STATUS/0x%02x",pkt.toApsn,topicHead, pkt.toLuid,pktStatus.oprId];
            return topic;
        }
        else
        {
            
        }
        
    }
    return topic;
}

+ (NSString* )getTopicHeadFromPkt:(XAIPKT*)pkt
{
    if ([XAILUIDUtil isServerAP:pkt.toLuid])
    {
       return @"GATEWAY";
    }
    else if ([XAILUIDUtil iSMobile:pkt.toLuid])
    {
        return @"MOBILES";
    }
   
    else if ([XAILUIDUtil isZigbee:pkt.toLuid])
    {
        return @"NODES";
    }
    else if ([XAILUIDUtil isVirtual:pkt.toLuid])
    {
        return @"VIRTUALS";
    }
    else
    {
        return nil;
    }
}

- (void)exit {
    kMQTTSessionManager.isProtection = false;
    //清除联动
    [kDataManager.linkageListenList removeAllObjects];
    [kDataManager.deviceListenList makeObjectsPerformSelector:@selector(unsubscribeDeviceStatus)];
    [kDataManager.deviceListenList removeAllObjects];
    //清除所有的包
    [kDataManager callBack];
    [kDataManager gatewayCallBack];
    [kDataManager linkageCallBack];
}

- (void)changeNewApsnAndNotify:(XAITYPEAPSN)apsn {
    [self changeNewApsn:apsn];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter]postNotificationName:kZTSwitchRootViewControllerKey object:@(1)];
    });
}
- (void)changeNewApsn:(XAITYPEAPSN)apsn
{
//    kMQTTSessionManager.currentUser.currentBindApsn = apsn;
//    [kMQTTSessionManager.currentUser archiver];
//    XAIGateway *findGateway = nil;
//    for (XAIGateway *gateway  in kDataManager.gatewayListenList) {
//        if (gateway.apsn == apsn)
//        {
//            findGateway = gateway;
//            break;
//        }
//    }
//    if (!findGateway) {
//        findGateway = [[XAIGateway alloc]initWithApsn:apsn Luid:kGATEWAYLUID];
//        [kDataManager addGateway:findGateway];
//    }
//    kMQTTSessionManager.currentGateway = findGateway;
//    [findGateway getGatewayStatus];
//    //订阅所有设备dev
//    [ZTDeviceUtil findAllDevWithApsn:apsn];
//    //订阅网关的好友ACTIVE
//    NSString *gatewyfriendTopic = [MQTTCoverTool gatewayConfigAllUserActiveTopicWithAPNS:apsn luid:kGATEWAYLUID];
//    [kMQTTSessionManager.mqttClient subscribe:gatewyfriendTopic withQos:ExactlyOnce];
//    //订阅网关的联动
//    [ZTLinkageUtil findAllLinkages: apsn luid:kGATEWAYLUID];
//    NSString *apsnStr= [MQTTCoverTool apsnToString:apsn];
//    NSSet *sets = [[NSSet alloc]initWithObjects:apsnStr, nil];
//    [JPUSHService setTags:sets callbackSelector:@selector(tags) object:nil];
//    [kDataManager gatewayCallBack];

}
#pragma mark - MQTTKeepAliveDelegate
- (void) didDisconnect
{

}
- (void) didConnect:(int)rc
{
   
}



+ (NSString *)roomListPath
{
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    ZTUser *user = kMQTTSessionManager.currentUser;
    NSString *str = [NSString stringWithFormat:@"roomList%@%08x.archiver",user.m_strTel,user.currentBindApsn];
    return [path stringByAppendingPathComponent:str];
}

#pragma mark - getters and setters
- (DataManager *)dataManager {
    if (!_dataManager) {
        _dataManager = [DataManager sharedManager];
    }
    return _dataManager;
}

- (dispatch_queue_t)historyMessageQueue {
    if (!_historyMessageQueue) {
        _historyMessageQueue = dispatch_queue_create("historyMessageQueue", DISPATCH_QUEUE_CONCURRENT);
    }
    return _historyMessageQueue;
}
@end
